#include <bits/stdc++.h>
#include <filesystem>
using namespace std;
namespace fs = std::filesystem;

struct Row {
    long long   k = 0;
    double      abs_mean = 0, mean_e_ns = 0, max_e_ns = 0, min_e_ns = 0;
    long double t_logic_ns = 0, t_raw_ns = 0, offset_ns = 0;
    bool        has_t_logic = false;
    bool        has_offset  = false;
};
struct Node {
    string file;
    string name;
    vector<Row> rows;
    // 统计汇总
    int total_rows = 0, used_rows = 0;
    double mean_avg = 0.0;
    double abs_mean_avg = 0.0;
    array<long long,5> cnt_max{};
    array<long long,5> cnt_min{};
    bool any_offset = false;
    double offset_avg = 0.0;
    long double offset_last = 0.0L;
};

static vector<string> split_csv_simple(const string& line){
    vector<string> out; string cur;
    for(char c: line){
        if(c==','){ out.push_back(cur); cur.clear(); }
        else cur.push_back(c);
    }
    out.push_back(cur);
    return out;
}

static bool parse_double(const string& s, double& v){ try{ size_t p=0; v=stod(s,&p); return p>0; }catch(...){return false;} }
static bool parse_ld(const string& s, long double& v){ try{ size_t p=0; v=stold(s,&p); return p>0; }catch(...){return false;} }
static bool parse_ll(const string& s, long long& v){ try{ size_t p=0; v=stoll(s,&p); return p>0; }catch(...){return false;} }

// ------- 美观输出小工具 -------
static string sep_i64(long long x){ string s=to_string(x),o; int n=s.size(); int sign=(s[0]=='-'); int cnt=0; for(int i=n-1;i>=sign;--i){ o.push_back(s[i]); if(++cnt==3 && i>sign){o.push_back(','); cnt=0;} } if(sign)o.push_back('-'); reverse(o.begin(),o.end()); return o; }
static string fmt_ns(double ns){ double a=fabs(ns); ostringstream oss; oss.setf(std::ios::fixed); oss<<setprecision(3); if(a>=1e6){oss<<(ns/1e6)<<" ms";} else if(a>=1e3){oss<<(ns/1e3)<<" µs";} else {oss<<ns<<" ns";} return oss.str(); }
static string pad(const string& s,int w){return (int)s.size()>=w? s: s+string(w-(int)s.size(),' ');}

static Node read_csv(const string& path){
    ifstream fin(path);
    if(!fin){ cerr<<"[ERR] cannot open "<<path<<"\n"; return {}; }

    string fname = fs::path(path).filename().string();
    string nodename;
    {
        regex r1(R"(metrics(\d+)\.csv)",regex::icase); smatch m;
        if(regex_search(fname,m,r1)) nodename=m[1].str();
        if(nodename.empty()){ regex r2(R"((\d+))"); if(regex_search(fname,m,r2)) nodename=m[1].str(); }
        if(nodename.empty()) nodename=fname;
    }

    string header; if(!getline(fin,header)) return {};
    auto cols=split_csv_simple(header);
    vector<string> norm=cols;
    for(auto &c:norm){ c.erase(remove_if(c.begin(),c.end(),::isspace),c.end()); transform(c.begin(),c.end(),c.begin(),::tolower); }
    auto find_idx=[&](initializer_list<const char*> names)->int{
        for(auto nm:names){ string key=nm; key.erase(remove_if(key.begin(),key.end(),::isspace),key.end()); transform(key.begin(),key.end(),key.begin(),::tolower);
            for(int i=0;i<(int)norm.size();++i) if(norm[i]==key) return i; } return -1; };

    int ik=find_idx({"k"});
    int iabs=find_idx({"abs_mean_e_ns","abs_mean","mean_abs_e_ns","mean_abs_e"});
    int imean=find_idx({"mean_e_ns","mean_e","meanerr_ns","mean_error_ns"});
    int imax=find_idx({"max_e_ns","max_e"});
    int imin=find_idx({"min_e_ns","min_e"});
    int itl=find_idx({"t_logic_after_ns","t_logic_before_ns","t_logic_ns","logic_after","logic_ns"});
    int itr=find_idx({"t_raw_ns","raw_ns","raw_time_ns"});
    int ioff=find_idx({"offset_after_ns","offset_before_ns","offset_ns","offset"});

    auto need_ok=[&](int i,const char*name){ if(i<0){ cerr<<"[ERR] missing col '"<<name<<"' in "<<path<<"\n"; return false;} return true; };
    if(!need_ok(ik,"k")||!need_ok(iabs,"abs_mean_e_ns")||!need_ok(imean,"mean_e_ns")||!need_ok(imax,"max_e_ns")||!need_ok(imin,"min_e_ns")) return {};

    Node node; node.file=path; node.name=nodename;
    string line;
    while(getline(fin,line)){
        if(line.empty()) continue;
        auto v=split_csv_simple(line);
        int need_max=max({ik,iabs,imean,imax,imin,max(itl,0),max(itr,0),max(ioff,0)});
        if((int)v.size()<=need_max) continue;
        Row r;
        if(!parse_ll(v[ik],r.k)) continue;
        parse_double(v[iabs],r.abs_mean);
        parse_double(v[imean],r.mean_e_ns);
        parse_double(v[imax],r.max_e_ns);
        parse_double(v[imin],r.min_e_ns);
        if(itl>=0) r.has_t_logic=parse_ld(v[itl],r.t_logic_ns);
        if(itr>=0) parse_ld(v[itr],r.t_raw_ns);
        if(ioff>=0) r.has_offset=parse_ld(v[ioff],r.offset_ns);
        node.rows.push_back(r);
    }
    return node;
}

static double average(const vector<double>& a){ if(a.empty()) return 0.0; long double s=0; for(double x:a) s+=x; return (double)(s/a.size()); }

int main(int argc,char**argv){
    ios::sync_with_stdio(false); cin.tie(nullptr);
    string dir="../data/all"; if(argc>1) dir=argv[1];
    int drop_head=1000, drop_tail=200;
    vector<long long> thresholds={1'000'000LL,500'000LL,200'000LL,100'000LL,50'000LL};

    vector<string> files;
    for(auto&e:fs::directory_iterator(dir)) if(e.is_regular_file()&&e.path().extension()==".csv") files.push_back(e.path().string());
    if(files.empty()){ cerr<<"[ERR] no CSV found in "<<dir<<"\n"; return 1; }

    vector<Node> nodes;
    for(auto &f:files){
        Node n=read_csv(f);
        if(n.rows.empty()) continue;
        n.total_rows=n.rows.size();
        if(n.total_rows<=drop_head+drop_tail) continue;
        int start=drop_head, end=n.total_rows-drop_tail, S=end-start;
        n.used_rows=S;

        vector<double> means, abss; means.reserve(S); abss.reserve(S);
        long double offset_sum=0; n.any_offset=false; n.offset_last=0;
        for(int i=start;i<end;++i){
            const auto&r=n.rows[i];
            means.push_back(r.mean_e_ns);
            abss.push_back(r.abs_mean);
            for(size_t t=0;t<thresholds.size();++t){
                if(r.max_e_ns>(double)thresholds[t]) n.cnt_max[t]++;
                if(r.min_e_ns<-(double)thresholds[t]) n.cnt_min[t]++;
            }
            if(r.has_offset){ offset_sum+=r.offset_ns; n.offset_last=r.offset_ns; n.any_offset=true; }
        }
        n.mean_avg=average(means);
        n.abs_mean_avg=average(abss);
        if(n.any_offset) n.offset_avg=(double)(offset_sum/(long double)S);
        nodes.push_back(move(n));
    }
    if(nodes.empty()){ cerr<<"[ERR] no valid csv.\n"; return 2; }

    // 全局统计
    long double sum_mean=0,sum_abs=0; long long cnt_mean=0;
    for(const auto&nd:nodes){ if(nd.used_rows<=0) continue; sum_mean+=nd.mean_avg*nd.used_rows; sum_abs+=nd.abs_mean_avg*nd.used_rows; cnt_mean+=nd.used_rows; }
    double global_mean=(cnt_mean>0)?(double)(sum_mean/cnt_mean):0.0;
    double global_abs =(cnt_mean>0)?(double)(sum_abs /cnt_mean):0.0;

    // -------- 输出表格 --------
    cout<<"\n========================= Per-Node Summary =========================\n";
    cout<<pad("Node",10)<<pad("used/total",14)<<pad("mean_e_avg",14)<<pad("|mean|_avg",14)
        <<pad(">100us",10)<<pad(">50us",10)<<pad("<-100us",10)<<pad("<-50us",10)
        <<pad("offset_avg",16)<<pad("offset_last",16)<<"\n";
    cout<<string(10+14+14+14+10+10+10+10+16+16,'-')<<"\n";

    for(const auto&nd:nodes){
        if(nd.used_rows<=0) continue;
        string used_tot=sep_i64(nd.used_rows)+"/"+sep_i64(nd.total_rows);
        cout<<pad(nd.name,10)
            <<pad(used_tot,14)
            <<pad(fmt_ns(nd.mean_avg),14)
            <<pad(fmt_ns(nd.abs_mean_avg),14)
            <<pad(sep_i64(nd.cnt_max[3]),10)
            <<pad(sep_i64(nd.cnt_max[4]),10)
            <<pad(sep_i64(nd.cnt_min[3]),10)
            <<pad(sep_i64(nd.cnt_min[4]),10)
            <<pad(nd.any_offset?fmt_ns(nd.offset_avg):"N/A",16)
            <<pad(nd.any_offset?fmt_ns(nd.offset_last):"N/A",16)
            <<"\n";
    }
    cout<<string(10+14+14+14+10+10+10+10+16+16,'-')<<"\n";
    cout<<"GLOBAL mean_e_ns avg: "<<fmt_ns(global_mean)
        <<" , |mean| avg: "<<fmt_ns(global_abs)
        <<"  ("<<sep_i64(cnt_mean)<<" samples)\n";

    // -------- 写 CSV --------
    ofstream fout("summary.csv");
    fout<<setprecision(9);
    fout<<"node,total_rows,used_rows,mean_e_ns_avg,abs_mean_e_ns_avg,"
           "max_e_ns_>1ms,max_e_ns_>500us,max_e_ns_>200us,max_e_ns_>100us,max_e_ns_>50us,"
           "min_e_ns_<-1ms,min_e_ns_<-500us,min_e_ns_<-200us,min_e_ns_<-100us,min_e_ns_<-50us,"
           "offset_last,offset_avg\n";
    for(const auto&nd:nodes){
        fout<<nd.name<<","<<nd.total_rows<<","<<nd.used_rows<<","
            <<nd.mean_avg<<","<<nd.abs_mean_avg<<","
            <<nd.cnt_max[0]<<","<<nd.cnt_max[1]<<","<<nd.cnt_max[2]<<","<<nd.cnt_max[3]<<","<<nd.cnt_max[4]<<","
            <<nd.cnt_min[0]<<","<<nd.cnt_min[1]<<","<<nd.cnt_min[2]<<","<<nd.cnt_min[3]<<","<<nd.cnt_min[4]<<",";
        if(nd.any_offset) fout<<(double)nd.offset_last<<","<<nd.offset_avg<<"\n";
        else fout<<","<<"\n";
    }
    fout<<"\nGLOBAL, , ,"<<global_mean<<","<<global_abs<<",,,,,,,,,,,,\n";
    fout.close();
    cout<<"[OK] Wrote summary.csv\n";
    return 0;
}
